home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
libs
/
intuisup.lha
/
Intuisup
/
source.lha
/
Menus
/
menus.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-03
|
15KB
|
493 lines
/* $Revision Header *** Header built automatically - do not edit! ***********
*
* (C) Copyright 1991 by Torsten Jürgeleit
*
* Name .....: menus.c
* Created ..: Thursday 19-Dec-91 18:02:58
* Revision .: 2
*
* Date Author Comment
* ========= ==================== ====================
* 03-Jun-92 Torsten Jürgeleit subitems now indicated by `»',
* alternate color for item texts,
* now correct item width calculated
* in init_menu()
* 20-Apr-92 Torsten Jürgeleit Enforcer hit in init_menu -> *key
* 19-Dec-91 Torsten Jürgeleit Created this file!
*
****************************************************************************
*
* Menu support routines
*
* $Revision Header ********************************************************/
/* Includes */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#ifdef AZTEC_C
#include <functions.h> /* needed for Aztec C - prototypes and pragmas for all Amiga system functions */
#endif
#include <libraries/memwatch.h> /* header file for memory debug link library (Fish 240) - AFTER functions.h */
#include <string.h>
#include "/render/render.h"
#include "/language/language.h"
#include "menus.h"
/* Static prototypes */
ULONG get_buffer_size(struct MenuList *ml);
VOID get_item_text_pens(struct MenuList *ml);
BOOL init_menu(struct MenuList *ml);
USHORT intui_text_length(BYTE *text, struct TextAttr *ta);
VOID equal_select_box_width(struct MenuItem *item);
/* Static pragmas */
#pragma regcall(get_buffer_size(a0))
#pragma regcall(get_item_text_pens(a0))
#pragma regcall(init_menu(a0))
#pragma regcall(intui_text_length(a0,a1))
#pragma regcall(equal_select_box_width(a0))
/* Create menu list */
struct MenuList *
create_menu(struct RenderInfo *ri, struct Window *win,
struct MenuData *md, struct TextAttr *ta, BYTE **language_text_array)
{
if (ri && ri->ri_ID == ISUP_ID && win && md) {
struct MenuList *ml;
if (ml = AllocMem((LONG)sizeof(struct MenuList),
(LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
struct TextFont *tf;
/* Init menu list struct */
ml->ml_RenderInfo = ri;
ml->ml_Window = win; /* needed for colors !!! */
ml->ml_Data = md;
ml->ml_TextAttr = ta;
ml->ml_LanguageTextArray = language_text_array;
ml->ml_Flags = 0;
ml->ml_ID = ISUP_ID;
/* Get font for menu texts */
if (ta) {
tf = OpenFont(ta);
} else {
tf = ri->ri_TextFont;
}
if (ml->ml_TextFont = tf) {
if (ml->ml_BufferSize = get_buffer_size(ml)) {
if (ml->ml_Buffer = AllocMem(ml->ml_BufferSize,
(LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
get_item_text_pens(ml);
if (init_menu(ml) == TRUE) {
return(ml);
}
FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
}
}
if (ta) {
CloseFont(tf);
}
}
FreeMem(ml, (LONG)sizeof(struct MenuList));
}
}
return(NULL);
}
/* Attach menu list to given window */
VOID
attach_menu(struct Window *win, struct MenuList *ml)
{
if (win && ml && ml->ml_ID == ISUP_ID) {
/* Remove menu strip from old window if any and attach it to new one */
if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
ClearMenuStrip(ml->ml_Window);
}
SetMenuStrip(win, (struct Menu *)ml->ml_Buffer);
ml->ml_Window = win;
ml->ml_Flags |= MENU_LIST_FLAG_ATTACHED;
}
}
/* Return menu item address */
struct MenuItem *
menu_item_address(struct MenuList *ml, USHORT menu_num)
{
struct MenuItem *mi = NULL;
if (ml && ml->ml_ID == ISUP_ID) {
mi = ItemAddress((struct Menu *)ml->ml_Buffer, (LONG)menu_num);
}
return(mi);
}
/* Remove menu list from window currently attached to */
struct Window *
remove_menu(struct MenuList *ml)
{
struct Window *win = NULL;
if (ml && ml->ml_ID == ISUP_ID) {
if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
win = ml->ml_Window;
ClearMenuStrip(win);
ml->ml_Flags &= ~MENU_LIST_FLAG_ATTACHED;
}
}
return(win);
}
/* Free menu */
VOID
free_menu(struct MenuList *ml)
{
if (ml && ml->ml_ID == ISUP_ID) {
if (ml->ml_Flags & MENU_LIST_FLAG_ATTACHED) {
ClearMenuStrip(ml->ml_Window);
}
if (ml->ml_TextAttr) {
CloseFont(ml->ml_TextFont);
}
FreeMem(ml->ml_Buffer, ml->ml_BufferSize);
FreeMem(ml, (LONG)sizeof(struct MenuList));
}
}
/* Get buffer size for menus, items and intui texts */
STATIC ULONG
get_buffer_size(struct MenuList *ml)
{
struct MenuData *md = ml->ml_Data;
ULONG buffer_size = 0;
if (md->md_Type != INTUISUP_DATA_END &&
md->md_Type == MENU_DATA_TYPE_TITLE) {
USHORT menus = 0, items = 0, subitem_texts = 0;
BOOL error = FALSE, subitem = FALSE;
do {
switch (md++->md_Type) {
case MENU_DATA_TYPE_TITLE :
menus++;
subitem = FALSE;
break;
case MENU_DATA_TYPE_ITEM :
items++;
subitem = FALSE;
break;
case MENU_DATA_TYPE_SUBITEM :
items++;
/* If first subitem then add text with `»' to previous item */
if (subitem == FALSE) {
subitem_texts++;
subitem = TRUE;
}
break;
default :
error = TRUE;
break;
}
} while (error == FALSE && md->md_Type != INTUISUP_DATA_END &&
md->md_Type <= MAX_MENU_DATA_TYPE);
if (error == FALSE && menus && items) {
buffer_size = menus * sizeof(struct Menu) + items *
(sizeof(struct MenuItem) + sizeof(struct IntuiText)) +
subitem_texts * sizeof(struct IntuiText);
}
}
return(buffer_size);
}
/* Get two different text pens for items */
STATIC VOID
get_item_text_pens(struct MenuList *ml)
{
struct RenderInfo *ri = ml->ml_RenderInfo;
SHORT num_colors;
if ((num_colors = 1 << ri->ri_ScreenDepth) > MAX_RENDER_COLORS) {
num_colors = MAX_RENDER_COLORS;
}
if (num_colors < 3) {
/* Set render pens for monochrome screen */
if (ml->ml_Window->BlockPen) {
ml->ml_TextPen1 = 0;
ml->ml_TextPen2 = 0;
} else {
ml->ml_TextPen1 = 1;
ml->ml_TextPen2 = 1;
}
} else {
struct ColorMap *cmap;
SHORT i, max_diff, back_color, colors[MAX_RENDER_COLORS],
pens[MAX_RENDER_COLORS];
/* Get current screen colors */
Forbid();
cmap = ml->ml_Window->WScreen->ViewPort.ColorMap;
for (i = 0; i < num_colors; i++) {
colors[i] = GetRGB4(cmap, (LONG)i);
pens[i] = i;
}
Permit();
/* Save normal background color */
back_color = colors[ml->ml_Window->BlockPen];
/* Set text pen 1 - search color with greatest `difference' to backgound color */
for (i = 0, max_diff = 0; i < num_colors; i++) {
SHORT diff;
if ((diff = calc_color_difference(colors[i], back_color)) >
max_diff) {
max_diff = diff;
ml->ml_TextPen1 = pens[i];
}
}
/* Set text pen 2 - search color with 2nd greatest `difference' to backgound color */
for (i = 0, max_diff = 0; i < num_colors; i++) {
SHORT diff;
if ((diff = calc_color_difference(colors[i], back_color)) >
max_diff && pens[i] != ri->ri_TextPen1) {
max_diff = diff;
ml->ml_TextPen2 = pens[i];
}
}
}
}
/* Initialize menu from menu list */
STATIC BOOL
init_menu(struct MenuList *ml)
{
struct RenderInfo *ri = ml->ml_RenderInfo;
struct TextFont *menu_tf = ri->ri_TextFont, *item_tf = ml->ml_TextFont;
struct TextAttr *menu_ta = &ri->ri_TextAttr, *item_ta = ml->ml_TextAttr;
struct MenuData *md;
struct Menu *last_menu, *menu = NULL; /* MUST be defined OUT of for loop */
struct MenuItem *last_item, *last_subitem, *item = NULL; /* MUST be defined OUT of for loop */
BYTE *buffer = ml->ml_Buffer;
SHORT item_ypos, subitem_xpos, subitem_ypos; /* MUST be defined OUT of for loop */
BOOL success = FALSE, error = FALSE, subitem_flag = FALSE;
/* Init menus and items */
for (md = ml->ml_Data; md->md_Type != INTUISUP_DATA_END &&
md->md_Type <= MAX_MENU_DATA_TYPE; md++) {
struct IntuiText *itext;
USHORT type, flags;
BYTE *name, *key;
/* Get data from menu data structure */
type = md->md_Type;
flags = md->md_Flags;
name = get_language_text(md->md_Text, ml->ml_LanguageTextArray);
key = (!md->md_CommandKey ? NULL :
get_language_text(md->md_CommandKey, ml->ml_LanguageTextArray));
/* Init structures according to data type */
switch (type) {
case MENU_DATA_TYPE_TITLE :
/* Prepare last menu and subitem list */
if (menu) {
equal_select_box_width(menu->FirstItem);
}
if (subitem_flag == TRUE) {
equal_select_box_width(last_item->SubItem);
}
/* Init data for new menu */
item = NULL;
last_item = NULL;
last_subitem = NULL;
item_ypos = 0;
subitem_flag = FALSE;
last_menu = menu;
menu = (struct Menu *)buffer;
buffer += sizeof(struct Menu);
/* Init new menu */
if (last_menu) {
/* If this isn't the first menu then connect it to last menu */
last_menu->NextMenu = menu;
menu->LeftEdge = last_menu->LeftEdge + last_menu->Width +
menu_tf->tf_XSize;
} else {
menu->LeftEdge = 5;
}
menu->Width = intui_text_length(name, menu_ta) +
menu_tf->tf_XSize;
menu->Height = menu_tf->tf_YSize;
menu->Flags = MIDRAWN | (flags & MENU_DATA_FLAG_DISABLED ?
0 : MENUENABLED);
menu->MenuName = name;
menu->FirstItem = (struct MenuItem *)buffer;
break;
case MENU_DATA_TYPE_ITEM :
case MENU_DATA_TYPE_SUBITEM :
/* Init item data */
if (subitem_flag == TRUE) {
last_subitem = item;
} else {
last_item = item;
}
item = (struct MenuItem *)buffer;
itext = (struct IntuiText *)(item + 1);
buffer += sizeof(struct MenuItem) + sizeof(struct IntuiText);
/* Init intui text */
itext->LeftEdge = (flags & MENU_DATA_FLAG_ATTRIBUTE ?
CHECKWIDTH : 0);
itext->TopEdge = 1;
itext->FrontPen = (flags & MENU_DATA_FLAG_TEXT_COLOR2 ?
ml->ml_TextPen2 : ml->ml_TextPen1);
itext->DrawMode = JAM1;
itext->ITextFont = item_ta;
itext->IText = (UBYTE *)name;
/* Init menu item */
item->Width = intui_text_length(name, item_ta) +
(key ? COMMWIDTH + 2 * item_tf->tf_XSize : 0) +
(flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKWIDTH : 0);
item->Height = item_tf->tf_YSize + 1;
item->Flags = ITEMTEXT | (key ? COMMSEQ : 0) |
(flags & MENU_DATA_FLAG_DISABLED ? 0 : ITEMENABLED) |
(flags & MENU_DATA_FLAG_HIGH_NONE ? HIGHNONE :
(flags & MENU_DATA_FLAG_HIGH_BOX ? HIGHBOX : HIGHCOMP)) |
(flags & MENU_DATA_FLAG_ATTRIBUTE ? CHECKIT : 0) |
(flags & MENU_DATA_FLAG_SELECTED ? CHECKED : 0);
item->MutualExclude = md->md_MutualExclude;
item->ItemFill = (APTR)itext;
item->SelectFill = (APTR)itext;
item->Command = (key ? *key : 0);
item->NextSelect = MENUNULL;
/* Insert empty line before item ? */
if (flags & MENU_DATA_FLAG_EMPTY_LINE) {
if (type == MENU_DATA_TYPE_SUBITEM) {
subitem_ypos += item->Height;
} else {
item_ypos += item->Height;
}
}
if (type == MENU_DATA_TYPE_SUBITEM) {
if (subitem_flag == TRUE) {
last_subitem->NextItem = item;
} else {
if (!last_item) {
error = TRUE; /* no menu item to attach subitem */
break;
} else {
struct IntuiText *new_itext,
*last_itext = (struct IntuiText *)
last_item->ItemFill;
/* Create intui text for sub item indicator `»' */
new_itext = (struct IntuiText *)buffer;
buffer += sizeof(struct IntuiText);
new_itext->TopEdge = last_itext->TopEdge;
new_itext->FrontPen = last_itext->FrontPen;
new_itext->DrawMode = JAM1;
new_itext->ITextFont = item_ta;
new_itext->IText = (UBYTE *)"»";
last_itext->NextText = new_itext;
/* Connect sub item to menu item */
last_item->Width += intui_text_length((BYTE *)
new_itext->IText, item_ta) + item_tf->tf_XSize;
last_item->SubItem = item;
subitem_xpos = intui_text_length((BYTE *)
last_itext->IText, item_ta) +
(last_item->Flags & CHECKIT ? CHECKWIDTH : 0);
subitem_ypos = 0;
subitem_flag = TRUE;
}
}
item->LeftEdge = subitem_xpos;
item->TopEdge = subitem_ypos;
subitem_ypos += item->Height;
} else {
if (last_item) {
last_item->NextItem = item;
}
item->TopEdge = item_ypos;
item_ypos += item->Height;
if (subitem_flag == TRUE) {
/* Prepare last subitem list */
equal_select_box_width(last_item->SubItem);
subitem_flag = FALSE;
}
}
break;
}
}
if (error == FALSE && item) {
/* Prepare current menu and subitem list */
equal_select_box_width(menu->FirstItem);
if (subitem_flag == TRUE) {
equal_select_box_width(last_item->SubItem);
}
success = TRUE;
}
return(success);
}
/* Calc text length in pixels */
STATIC USHORT
intui_text_length(BYTE *text, struct TextAttr *ta)
{
struct IntuiText itext;
/* Init dummy intui text and return text length */
itext.IText = (UBYTE *)text;
itext.ITextFont = ta;
return(IntuiTextLength(&itext));
}
/* Set equal select box width for given menu item list */
STATIC VOID
equal_select_box_width(struct MenuItem *item)
{
struct MenuItem *save_item = item;
ULONG max_width = 0;
/* Search max width */
do {
if (item->Width > max_width) {
max_width = item->Width;
}
} while (item = item->NextItem);
/* Set max width */
item = save_item;
do {
item->Width = max_width;
/* If subitem then calc left edge of subitem indicator `»' */
if (item->SubItem) {
struct IntuiText *itext = ((struct IntuiText *)
item->ItemFill)->NextText;
itext->LeftEdge = max_width - intui_text_length((BYTE *)
itext->IText, itext->ITextFont);
}
} while (item = item->NextItem);
}